package com.rede.didiok.user.modulelist.pay.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rede.didiok.common.constant.conf.SysConf;
import com.rede.didiok.common.constant.conf.base.BaseSQLConf;
import com.rede.didiok.common.constant.conf.base.BaseSysConf;
import com.rede.didiok.common.constant.global.Constants;
import com.rede.didiok.common.domainEvent.EventAction;
import com.rede.didiok.common.dto.pay.PayOrderDto;
import com.rede.didiok.common.dto.rank.RankMemberDto;
import com.rede.didiok.common.dto.user.UserDto;
import com.rede.didiok.common.enums.OrderApplyTypeEnum;
import com.rede.didiok.common.enums.OrderStatusEnum;
import com.rede.didiok.common.enums.PayMethodEnum;
import com.rede.didiok.common.enums.StatusEnum;
import com.rede.didiok.common.exception.exceptionType.QueryException;
import com.rede.didiok.common.exception.exceptionType.UpdateException;
import com.rede.didiok.common.feign.FileFeignClient;
import com.rede.didiok.common.feign.RankFeignClient;
import com.rede.didiok.common.feign.UserFeignClient;
import com.rede.didiok.common.holder.RequestHolder;
import com.rede.didiok.common.schema.ProductDto;
import com.rede.didiok.common.service.impl.SuperServiceImpl;
import com.rede.didiok.common.utils.JsonUtils;
import com.rede.didiok.common.utils.ListUtils;
import com.rede.didiok.common.utils.StringUtils;
import com.rede.didiok.common.utils.business.DomainEventUtil;
import com.rede.didiok.common.utils.business.IdGenerator;
import com.rede.didiok.common.utils.business.WebUtil;
import com.rede.didiok.user.modulelist.pay.dao.PayOrderDao;
import com.rede.didiok.user.modulelist.pay.entity.PayOrderEntity;
import com.rede.didiok.user.modulelist.pay.global.SQLConf;
import com.rede.didiok.user.modulelist.pay.model.bean.LanTuWxPayBean;
import com.rede.didiok.user.modulelist.pay.service.PayOrderService;
import com.rede.didiok.user.modulelist.pay.utils.LantuPayUtil;
import com.rede.didiok.user.modulelist.rank.dao.AttrInfoDao;
import com.rede.didiok.user.modulelist.rank.dao.RankMemberDao;
import com.rede.didiok.user.modulelist.rank.entity.AttrInfoEntity;
import com.rede.didiok.user.modulelist.rank.entity.RankMemberEntity;
import com.rede.didiok.user.modulelist.rank.service.RankMemberService;

/**
 * 支付订单实现类
 *
 * @author 陌溪
 * @date 2023年4月25日22:21:35
 */
@Slf4j
@RefreshScope
@Service("payOrderService")
public class PayOrderServiceImpl extends SuperServiceImpl<PayOrderDao, PayOrderEntity> implements PayOrderService {

    @Resource
    private PayOrderService payOrderService;
    @Autowired
    private IdGenerator idGenerator;
    @Resource
    private UserFeignClient userFeignClient;
    @Resource
    private RankFeignClient rankFeignClient;
    @Resource
    private FileFeignClient fileFeignClient;
    @Resource
    private RankMemberService rankMemberService;
    @Resource
    private WebUtil webUtil;
    @Resource
    private DomainEventUtil domainEventUtil;

    @Resource
    private AttrInfoDao attrInfoDao;
    @Resource
    private RankMemberDao rankMemberDao;
    @Resource
    private LanTuWxPayBean lanTuWxPayBean;

    private static final String REFUND_URL = "https://api.ltzf.cn/api/wxpay/refund_order";

    private static final String LANTU_REFUND_NOTIFY_URL = "/trade/lantuWxPay/callback/refund";

    @Override
    public IPage<PayOrderEntity> getPageList(PayOrderDto payOrderVO) {
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();

        if (StringUtils.isNotEmpty(payOrderVO.getResourceType())) {
            queryWrapper.eq(SQLConf.RESOURCE_TYPE, payOrderVO.getResourceType());
        }
        if (payOrderVO.getPayType() != null) {
            queryWrapper.eq(SQLConf.PAY_TYPE, payOrderVO.getPayType());
        }
        if (payOrderVO.getPayMethod() != null) {
            queryWrapper.eq(SQLConf.PAY_METHOD, payOrderVO.getPayMethod());
        }
        if (StringUtils.isNotEmpty(payOrderVO.getKeyword())) {
            queryWrapper.or().eq(BaseSQLConf.ORDER_NO, payOrderVO.getKeyword()).or().eq(BaseSQLConf.USER_UID, payOrderVO.getKeyword()).or().eq(SQLConf.RESOURCE_UID, payOrderVO.getKeyword());
        }
        if (payOrderVO.getOrderStatus() != null) {
            queryWrapper.eq(SQLConf.ORDER_STATUS, payOrderVO.getOrderStatus());
        }

        queryWrapper.eq(BaseSQLConf.STATUS, StatusEnum.ENABLE);
        List<PayOrderEntity> payOrderList = new ArrayList<>();
        IPage<PayOrderEntity> payOrderIPage = new Page<>();
        // 如果要计算累积排行
        if (StringUtils.isNotEmpty(payOrderVO.getOrderByDescColumn()) && SQLConf.SUM.equals(payOrderVO.getOrderByDescColumn())) {
            queryWrapper.groupBy(SQLConf.CREATE_USER_UID);
            queryWrapper.last(SysConf.LIMIT_ONE);
            int count = payOrderService.count(queryWrapper);
            queryWrapper.last("");
            queryWrapper.orderByDesc(SQLConf.PRICE);
            Page<Map<String, Object>> orderPage = new Page<>(payOrderVO.getCurrentPage(), payOrderVO.getPageSize());
            List<Map<String, Object>> records = payOrderService.pageMaps(orderPage, queryWrapper
                    .select(SQLConf.CREATE_USER_UID, "SUM(price) AS price")
                    .orderByDesc(SQLConf.PRICE)).getRecords();
            // 将查询结果转换为自定义数据类型
            payOrderList = records.stream().map(record -> {
                PayOrderEntity d = new PayOrderEntity();
                d.setCreateUserUid((String) record.get(SQLConf.CREATE_USER_UID));
                Double dd = Double.valueOf(record.get(SQLConf.PRICE).toString());
                d.setTotalPrice(BigDecimal.valueOf(dd).setScale(2,BigDecimal.ROUND_HALF_UP));
                return d;
            }).collect(Collectors.toList());
            payOrderIPage.setRecords(payOrderList);
            payOrderIPage.setTotal(count);
            payOrderIPage.setCurrent(payOrderVO.getCurrentPage());
            payOrderIPage.setSize(payOrderVO.getPageSize());
        } else {
            if (StringUtils.isNotEmpty(payOrderVO.getOrderByAscColumn())) {
                // 将驼峰转换成下划线
                String column = StringUtils.underLine(new StringBuffer(payOrderVO.getOrderByAscColumn())).toString();
                queryWrapper.orderByAsc(column);
            } else if (StringUtils.isNotEmpty(payOrderVO.getOrderByDescColumn())) {
                // 将驼峰转换成下划线
                String column = StringUtils.underLine(new StringBuffer(payOrderVO.getOrderByDescColumn())).toString();
                queryWrapper.orderByDesc(column);
            } else {
                queryWrapper.orderByDesc(SQLConf.CREATE_TIME);
            }
            Page<PayOrderEntity> page = new Page<>();
            page.setCurrent(payOrderVO.getCurrentPage());
            page.setSize(payOrderVO.getPageSize());
            payOrderIPage = payOrderService.page(page, queryWrapper);
            payOrderList = payOrderIPage.getRecords();
        }

        List<String> userUidList = new ArrayList<>();
        for (PayOrderEntity payOrder : payOrderList) {
            if (StringUtils.isNotEmpty(payOrder.getSnapshot())) {
                ProductDto productVO = JsonUtils.jsonToPojo(payOrder.getSnapshot(), ProductDto.class);
                payOrder.setProductVO(productVO);
            }
            if (StringUtils.isNotEmpty(payOrder.getCreateUserUid())) {
                userUidList.add(payOrder.getCreateUserUid());
            }
        }

        // 获取用户信息
        List<UserDto> userList = new ArrayList<>();
        if (userUidList.size() > 0) {
            UserDto userVO = new UserDto();
            userVO.setUserUidList(userUidList);
            userVO.setPageSize((long)userUidList.size());
            userVO.setCurrentPage(1L);
            List<UserDto> result = userFeignClient.getUserListByPage(userVO);
            if (result != null) {
                userList = result;
            }
        }

        Map<String, UserDto> userMap = new HashMap<>();
        if (userList.size() > 0) {
            for (UserDto user : userList) {
                userMap.put(user.getUid(), user);
            }
        }

        for (PayOrderEntity payOrder : payOrderList) {
            if (StringUtils.isEmpty(payOrder.getCreateUserUid())) {
                continue;
            }
            payOrder.setUser(userMap.get(payOrder.getCreateUserUid()));
        }
        return payOrderIPage;
    }

    @Override
    public IPage<PayOrderEntity> listMyOrder(PayOrderDto payOrderVO) {
        // 获取当前用户的userUid
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            throw new QueryException(Constants.USER_UID_EMPTY);
        }
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(payOrderVO.getKeyword())) {
            queryWrapper.like(SQLConf.TITLE, payOrderVO.getKeyword().trim());
        }

        if (userUid != null) {
            queryWrapper.eq(SQLConf.CREATE_USER_UID, userUid);
        }

        queryWrapper.eq(BaseSQLConf.STATUS, StatusEnum.ENABLE);
        // 允许查看报名成功或者由活动举办方取消的订单
        if(payOrderVO.getOrderStatus() == null) {
            List<Integer> statusList = new ArrayList<>();
            statusList.add(OrderStatusEnum.PaySuccess);
            statusList.add(OrderStatusEnum.OrganizerCancel);
            statusList.add(OrderStatusEnum.Cancelling);
            statusList.add(OrderStatusEnum.Finish);
            queryWrapper.and(wrapper -> wrapper.in(SQLConf.ORDER_STATUS, statusList));
        }else {
            queryWrapper.and(wrapper -> wrapper.eq(SQLConf.ORDER_STATUS, payOrderVO.getOrderStatus()));
        }
        List<PayOrderEntity> payOrderList = new ArrayList<>();
        IPage<PayOrderEntity> payOrderIPage = new Page<>();

        if (StringUtils.isNotEmpty(payOrderVO.getOrderByAscColumn())) {
            // 将驼峰转换成下划线
            String column = StringUtils.underLine(new StringBuffer(payOrderVO.getOrderByAscColumn())).toString();
            queryWrapper.orderByAsc(column);
        } else if (StringUtils.isNotEmpty(payOrderVO.getOrderByDescColumn())) {
            // 将驼峰转换成下划线
            String column = StringUtils.underLine(new StringBuffer(payOrderVO.getOrderByDescColumn())).toString();
            queryWrapper.orderByDesc(column);
        } else {
            queryWrapper.orderByDesc(SQLConf.CREATE_TIME);
        }
        Page<PayOrderEntity> page = new Page<>();
        page.setCurrent(payOrderVO.getCurrentPage());
        page.setSize(payOrderVO.getPageSize());
        payOrderIPage = payOrderService.page(page, queryWrapper);
        payOrderList = payOrderIPage.getRecords();

        List<String> resourceUidList = payOrderList.stream().map(PayOrderEntity::getResourceUid).collect(Collectors.toList());

        RankMemberDto rankMemberDto = new RankMemberDto();
        rankMemberDto.setUids(resourceUidList);
        // 根据userUid和keyword  查询 RankMemberDto 的title和Uid
        String jsonStr = rankFeignClient.listRankMemberUid(rankMemberDto);
        List<RankMemberDto> rankMemberDtoList = new ArrayList<>();
        final StringBuffer fileUids = new StringBuffer();

        Map<String, String> uidTitleMap = new HashMap<>(Constants.NUM_EIGHT);
        Map<String, String> uidFileUidMap = new HashMap<>(Constants.NUM_EIGHT);
        Map<String, Object> dataMap = (Map<String, Object>) JsonUtils.jsonToObject(jsonStr, Map.class);
        if (BaseSysConf.SUCCESS.equals(dataMap.get(BaseSysConf.CODE))) {
            String jsonList = JsonUtils.objectToJson(dataMap.get(BaseSysConf.DATA));
            rankMemberDtoList = JSONArray.parseArray(jsonList, RankMemberDto.class);
            for(RankMemberDto item : rankMemberDtoList){
                if (StringUtils.isNotEmpty(item.getFileUid())) {
                    fileUids.append(item.getFileUid() + SysConf.FILE_SEGMENTATION);
                }
                uidTitleMap.put(item.getUid(), item.getTitle());
                // 图片的map
                uidFileUidMap.put(item.getUid(), item.getFileUid());
            }
        }

        // 查询图片
        String pictureList = null;
        if (fileUids != null) {
            pictureList = fileFeignClient.getPicture(fileUids.toString(), SysConf.FILE_SEGMENTATION);
        }

        List<Map<String, Object>> picList = webUtil.getPictureMap(pictureList);
        Map<String, String> pictureMap = picList.stream().collect(Collectors.toMap(k -> k.get(SQLConf.UID).toString(), v -> v.get(SQLConf.URL).toString()));

        for (PayOrderEntity payOrder : payOrderList) {
            payOrder.setApplyTypeName(OrderApplyTypeEnum.getNameByCode(payOrder.getApplyType()));
            if (StringUtils.isNotEmpty(payOrder.getSnapshot())) {
                ProductDto productVO = JsonUtils.jsonToPojo(payOrder.getSnapshot(), ProductDto.class);
                payOrder.setProductVO(productVO);
            }
            String title = uidTitleMap.get(payOrder.getResourceUid());
            if(null != title && !title.equals(payOrder.getTitle())) {
                payOrder.setNewTitle(title);
            }
            payOrder.setOid(payOrder.getResourceOid());

            // 设置标题图
            String fileUid = uidFileUidMap.get(payOrder.getResourceUid());
            if (StringUtils.isNotEmpty(fileUid)) {
                List<String> pictureUidsTemp = StringUtils.changeStringToString(fileUid, SysConf.FILE_SEGMENTATION);
                List<String> pictureListTemp = new ArrayList<>();

                pictureUidsTemp.forEach(picture -> {
                    pictureListTemp.add(pictureMap.get(picture));
                });
                // 只设置一张标题图
                if (pictureListTemp.size() > 0) {
                    payOrder.setPhotoUrl(pictureListTemp.get(0));
                } else {
                    payOrder.setPhotoUrl("");
                }
            }
        }

        return payOrderIPage;
    }

    @Override
    public PayOrderEntity getOrderDetail(PayOrderDto payOrderVO) {
        PayOrderEntity orderEntity = this.getById(payOrderVO.getUid());
        orderEntity.setApplyTypeName(OrderApplyTypeEnum.getNameByCode(orderEntity.getApplyType()));

        String resourceUid = orderEntity.getResourceUid();

        // TODO 从redis中获取活动的标题图和标题：CommonDataDto: photoUrl, name

        // 查询活动详情
        RankMemberEntity memberEntity = rankMemberService.getRankMemberById(resourceUid);

        orderEntity.setPhotoUrl(memberEntity.getPhotoUrl());
        orderEntity.setTitle(memberEntity.getTitle());
        orderEntity.setOrganizerUserUid(memberEntity.getCreateUserUid());

        // 查询图片
        String fileUid = memberEntity.getFileUid();
        if (StringUtils.isEmpty(fileUid)) {
            return orderEntity;
        }

        String pictureList = fileFeignClient.getPicture(fileUid, SysConf.FILE_SEGMENTATION);
        List<Map<String, Object>> picList = webUtil.getPictureMap(pictureList);
        Map<String, String> pictureMap = picList.stream().collect(Collectors.toMap(k -> k.get(SQLConf.UID).toString(), v -> v.get(SQLConf.URL).toString()));

        // 设置标题图
        List<String> pictureUidsTemp = StringUtils.changeStringToString(fileUid, SysConf.FILE_SEGMENTATION);
        List<String> pictureListTemp = new ArrayList<>();

        pictureUidsTemp.forEach(picture -> {
            pictureListTemp.add(pictureMap.get(picture));
        });
        // 只设置一张标题图
        if (pictureListTemp.size() > 0) {
            orderEntity.setPhotoUrl(pictureListTemp.get(0));
        } else {
            orderEntity.setPhotoUrl("");
        }
        return orderEntity;

    }

    @Override
    public IPage<PayOrderEntity> listOrderOfMyRankMember(PayOrderDto payOrderVO) {
        // 获取当前用户的userUid
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            throw new QueryException(Constants.USER_UID_EMPTY);
        }
        // 查询我发起的活动
        RankMemberDto rankMemberDto = new RankMemberDto();
        rankMemberDto.setCreateUserUid(userUid);
        if(StringUtils.isNotEmpty(payOrderVO.getKeyword())){
            rankMemberDto.setKeyword(payOrderVO.getKeyword());
        }
        rankMemberDto.setStatus(StatusEnum.ENABLE);
        // 根据userUid和keyword  查询 RankMemberDto 的title和Uid
        String jsonStr = rankFeignClient.listRankMemberUid(rankMemberDto);
        List<RankMemberDto> rankMemberDtoList = new ArrayList<>();
        List<String> memberUids = new ArrayList<>();
        final StringBuffer fileUids = new StringBuffer();

        Map<String, String> uidTitleMap = new HashMap<>(Constants.NUM_EIGHT);
        Map<String, String> uidFileUidMap = new HashMap<>(Constants.NUM_EIGHT);
        Map<String, Object> dataMap = (Map<String, Object>) JsonUtils.jsonToObject(jsonStr, Map.class);
        if (BaseSysConf.SUCCESS.equals(dataMap.get(BaseSysConf.CODE))) {
            String jsonList = JsonUtils.objectToJson(dataMap.get(BaseSysConf.DATA));
            rankMemberDtoList = JSONArray.parseArray(jsonList, RankMemberDto.class);
            for(RankMemberDto item : rankMemberDtoList){
                memberUids.add(item.getUid());
                if (StringUtils.isNotEmpty(item.getFileUid())) {
                    fileUids.append(item.getFileUid() + SysConf.FILE_SEGMENTATION);
                }
                uidTitleMap.put(item.getUid(), item.getTitle());
                // 图片的map
                uidFileUidMap.put(item.getUid(), item.getFileUid());
            }
//            uidTitleMap = rankMemberDtoList.stream().collect(Collectors.toMap(RankMemberDto::getUid, RankMemberDto::getTitle, (e1, e2) -> e2));
        }

        if(ListUtils.isEmpty(memberUids)){
            return new Page<>();
        }
        // TODO 查询订单和查询图片 可实现并行

        // 查询图片
        String pictureList = null;
        if (fileUids != null) {
            pictureList = fileFeignClient.getPicture(fileUids.toString(), SysConf.FILE_SEGMENTATION);
        }

        List<Map<String, Object>> picList = webUtil.getPictureMap(pictureList);
        Map<String, String> pictureMap = picList.stream().collect(Collectors.toMap(k -> k.get(SQLConf.UID).toString(), v -> v.get(SQLConf.URL).toString()));

//        picList.forEach(item -> {
//            pictureMap.put(item.get(SQLConf.UID).toString(), item.get(SQLConf.URL).toString());
//        });
        // 查询订单
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();

        queryWrapper.in(SQLConf.RESOURCE_UID, memberUids);
        // 允许查看报名成功或者由活动举办方取消的订单
        if(payOrderVO.getOrderStatus() == null) {
            List<Integer> statusList = new ArrayList<>();
            statusList.add(OrderStatusEnum.PaySuccess);
            statusList.add(OrderStatusEnum.OrganizerCancel);
            statusList.add(OrderStatusEnum.Cancelling);
            statusList.add(OrderStatusEnum.Finish);
            queryWrapper.and(wrapper -> wrapper.in(SQLConf.ORDER_STATUS, statusList));
        }else {
            queryWrapper.and(wrapper -> wrapper.eq(SQLConf.ORDER_STATUS, payOrderVO.getOrderStatus()));
        }
        queryWrapper.eq(BaseSQLConf.STATUS, StatusEnum.ENABLE);
        List<PayOrderEntity> payOrderList = new ArrayList<>();
        IPage<PayOrderEntity> payOrderIPage = new Page<>();

        if (StringUtils.isNotEmpty(payOrderVO.getOrderByAscColumn())) {
            // 将驼峰转换成下划线
            String column = StringUtils.underLine(new StringBuffer(payOrderVO.getOrderByAscColumn())).toString();
            queryWrapper.orderByAsc(column);
        } else if (StringUtils.isNotEmpty(payOrderVO.getOrderByDescColumn())) {
            // 将驼峰转换成下划线
            String column = StringUtils.underLine(new StringBuffer(payOrderVO.getOrderByDescColumn())).toString();
            queryWrapper.orderByDesc(column);
        } else {
            queryWrapper.orderByDesc(SQLConf.CREATE_TIME);
        }
        // 获取最终生成的SQL语句
//        String sql = queryWrapper.getSqlSegment();
//        System.out.println(sql);

        Page<PayOrderEntity> page = new Page<>();
        page.setCurrent(payOrderVO.getCurrentPage());
        page.setSize(payOrderVO.getPageSize());
        payOrderIPage = payOrderService.page(page, queryWrapper);
        payOrderList = payOrderIPage.getRecords();

        for (PayOrderEntity payOrder : payOrderList) {
            payOrder.setApplyTypeName(OrderApplyTypeEnum.getNameByCode(payOrder.getApplyType()));

            if (StringUtils.isNotEmpty(payOrder.getSnapshot())) {
                ProductDto productVO = JsonUtils.jsonToPojo(payOrder.getSnapshot(), ProductDto.class);
                payOrder.setProductVO(productVO);
            }
            String title = uidTitleMap.get(payOrder.getResourceUid());
            if(StringUtils.isNotEmpty(title)) {
                payOrder.setTitle(title);
            }
            payOrder.setOid(payOrder.getResourceOid());

            // 设置标题图
            String fileUid = uidFileUidMap.get(payOrder.getResourceUid());
            if (StringUtils.isNotEmpty(fileUid)) {
                List<String> pictureUidsTemp = StringUtils.changeStringToString(fileUid, SysConf.FILE_SEGMENTATION);
                List<String> pictureListTemp = new ArrayList<>();

                pictureUidsTemp.forEach(picture -> {
                    pictureListTemp.add(pictureMap.get(picture));
                });
                // 只设置一张标题图
                if (pictureListTemp.size() > 0) {
                    payOrder.setPhotoUrl(pictureListTemp.get(0));
                } else {
                    payOrder.setPhotoUrl("");
                }

                payOrder.setOrganizerUserUid(userUid);
            }
        }

        return payOrderIPage;
    }

    @Override
    public int getPayOrderCount(PayOrderDto payOrderVO) {
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(payOrderVO.getResourceType())) {
            queryWrapper.eq(SQLConf.RESOURCE_TYPE, payOrderVO.getResourceType());
        }
        if (StringUtils.isNotEmpty(payOrderVO.getResourceUid())) {
            queryWrapper.eq(SQLConf.RESOURCE_UID, payOrderVO.getResourceUid());
        }
        if (StringUtils.isNotEmpty(payOrderVO.getUid())) {
            queryWrapper.eq(BaseSQLConf.UID, payOrderVO.getUid());
        }
        if (payOrderVO.getPayType() != null) {
            queryWrapper.eq(BaseSQLConf.PAY_TYPE, payOrderVO.getPayType());
        }
        if (StringUtils.isNotEmpty(payOrderVO.getCreateUserUid())) {
            queryWrapper.eq(BaseSQLConf.USER_UID, payOrderVO.getCreateUserUid());
        }
        if (payOrderVO.getOrderStatus() != null) {
            queryWrapper.eq(SQLConf.ORDER_STATUS, payOrderVO.getOrderStatus());
        }
        queryWrapper.eq(BaseSQLConf.STATUS, StatusEnum.ENABLE);
        return payOrderService.count(queryWrapper);
    }

    @Override
    public int getPayOrderSumFee(PayOrderDto payOrderVO) {
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(payOrderVO.getResourceType())) {
            queryWrapper.eq(SQLConf.RESOURCE_TYPE, payOrderVO.getResourceType());
        }
        if (StringUtils.isNotEmpty(payOrderVO.getResourceUid())) {
            queryWrapper.eq(SQLConf.RESOURCE_UID, payOrderVO.getResourceUid());
        }
        if (payOrderVO.getPayType() != null) {
            queryWrapper.eq(BaseSQLConf.PAY_TYPE, payOrderVO.getPayType());
        }
        if (StringUtils.isNotEmpty(payOrderVO.getUid())) {
            queryWrapper.eq(BaseSQLConf.UID, payOrderVO.getUid());
        }
        if (StringUtils.isNotEmpty(payOrderVO.getCreateUserUid())) {
            queryWrapper.eq(BaseSQLConf.USER_UID, payOrderVO.getCreateUserUid());
        }
        if (payOrderVO.getOrderStatus() != null) {
            queryWrapper.eq(SQLConf.ORDER_STATUS, payOrderVO.getOrderStatus());
        }
        queryWrapper.eq(BaseSQLConf.STATUS, StatusEnum.ENABLE);
        queryWrapper.select("sum(price) as total", SQLConf.CREATE_USER_UID);
        queryWrapper.groupBy(SQLConf.CREATE_USER_UID);
        Map<String, Object> payOrderMap = payOrderService.getMap(queryWrapper);
        BigDecimal bigDecimal = (BigDecimal) payOrderMap.get("total");
        return bigDecimal.intValue();
    }

    @Override
    public boolean checkWhetherPay(String productUid, String orderUid) {

        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            return false;
        }
        LambdaQueryWrapper<PayOrderEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PayOrderEntity::getCreateUserUid, userUid);
        queryWrapper.eq(PayOrderEntity::getOrderStatus, OrderStatusEnum.PaySuccess);
        if (StringUtils.isNotEmpty(orderUid)) {
            queryWrapper.eq(PayOrderEntity::getUid, orderUid);
        } else {
            queryWrapper.eq(PayOrderEntity::getResourceUid, productUid);
        }
        queryWrapper.last(SysConf.LIMIT_ONE);
        PayOrderEntity payOrder = this.getOne(queryWrapper);
        return payOrder != null;
    }

    /**
     * 活动主办方取消某人报名
     *
     * @param payOrderVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean organizerCancelOrder(PayOrderDto payOrderVO) {
        // TODO 校验当前用户是否是活动主办方

        // 获取当前用户的userUid
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            throw new QueryException(Constants.USER_UID_EMPTY);
        }
        String userName = RequestHolder.getUserName();
        log.info("userUid:{}, organizerUserUid:{}", userUid,payOrderVO.getOrganizerUserUid());
        if(!userUid.equals(payOrderVO.getOrganizerUserUid())){
            throw new UpdateException("不好意思，您无权操作!");
        }

        PayOrderEntity payOrderEntity = this.getOne(new LambdaQueryWrapper<PayOrderEntity>()
                .eq(PayOrderEntity::getUid, payOrderVO.getUid()).eq(PayOrderEntity::getResourceUid, payOrderVO.getResourceUid())
        );
        if (payOrderEntity == null) {
            throw new UpdateException("未查询到此人的报名信息,请刷新页面后操作");
        }
        // 校验当前活动是否已结束
        String resourceUid = payOrderEntity.getResourceUid();
        if(StringUtils.isNotEmpty(resourceUid)){
            // 获取活动时间
            AttrInfoEntity attrInfoEntity = attrInfoDao.getActivityEndTimeByMemberUid(resourceUid);
            if(attrInfoEntity == null && attrInfoEntity.getEndTime() == null){
                throw new QueryException("活动结束时间获取异常");
            }
            if(attrInfoEntity.getEndTime().before(new Date())){
                throw new QueryException("活动已结束，无法取消报名");
            }
        }

//        payOrderEntity.setOrderStatus(OrderStatusEnum.OrganizerCancel);
//        Boolean isSave = payOrderEntity.updateById();
//
//        // 订单取消成功
//        if (isSave) {
//
//
//        }

        // TODO 校验付款时间和当前时间对比，超过15天，不允许退款


        payOrderEntity.setUserName(userName);
        payOrderEntity.setOperateUserUid(userUid);
        payOrderEntity.setOrganizerUserUid(payOrderVO.getOrganizerUserUid());
        // 将支付的费用原路退回
        String result = refundForCancel(payOrderEntity);

//        if(null == result) {
            // 发送订单取消成功通知
//            PayOrderDto dto = new PayOrderDto();
//            BeanUtils.copyProperties(payOrderEntity, dto);
//            dto.setUserName(userName);
//            dto.setOperateUserUid(userUid);
//            dto.setOrganizerUserUid(payOrderVO.getOrganizerUserUid());
//            log.info("发送订单取消成功通知:{}", JSONObject.toJSONString(dto));
//            domainEventUtil.publishEvent(EventAction.ORDER_CANCEL_SUCCESS, dto);
        if(StringUtils.isNotEmpty(result)) {
            log.error("调用蓝兔支付的退款接口失败：可能余额不足，也可能超过15天允许退款的时限");
//            throw new FeignException("第三方退款接口响应失败");
            throw new UpdateException("退款失败，请联系管理员！");
        }
        return true;
    }

    /**
     * 活动主办方取消某人报名
     *
     * @param resourceUid
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<String> cancelPayOrderByResourceUid(String resourceUid, String organizerUserUid) {

        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.RESOURCE_UID, resourceUid);
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        // 只获取uid信息
//        queryWrapper.select(SQLConf.RESOURCE_UID, SQLConf.UID);
        List<PayOrderEntity> list = this.list(queryWrapper);

        // 没有此活动的报名信息，直接返回
        if (ListUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
//        List<PayOrderEntity> updateList = list.stream().map(item -> {
//            PayOrderEntity order = new PayOrderEntity();
//            order.setUid(item.getUid());
//            order.setOrderStatus(OrderStatusEnum.OrganizerCancel);
//            return order;
//        }).collect(Collectors.toList());
//
//        boolean flag = this.updateBatchById(updateList);
//        if(!flag) {
//            throw new UpdateException("活动取消失败");
//        }
        // 获取当前用户的userUid
        String userUid = RequestHolder.getUserUid();
        if (StringUtils.isEmpty(userUid)) {
            throw new QueryException(Constants.USER_UID_EMPTY);
        }
        String userName = RequestHolder.getUserName();
        if (StringUtils.isEmpty(organizerUserUid)) {
            organizerUserUid = userUid;
        }
        for(PayOrderEntity orderEntity : list){
            orderEntity.setUserName(userName);
            orderEntity.setOperateUserUid(userUid);
            orderEntity.setOrganizerUserUid(organizerUserUid);
        }
        //  将支付的费用原路返回
        List<String> result = refundForCancelList(list);
        return result;
    }

    /**
     * 将支付的费用原路退回，如退还失败，返回订单号
     * @param payOrderEntity
     */
    public String refundForCancel(PayOrderEntity payOrderEntity) {
        // 付款方式为蓝图支付，并且状态为付款成功的才要退款
        if (payOrderEntity == null
                || payOrderEntity.getPayMethod() == null
                || payOrderEntity.getPayMethod() != PayMethodEnum.LANTU_WECHAT_PAY.getType()
                || !OrderStatusEnum.PaySuccess.equals(payOrderEntity.getOrderStatus())) {
            return null;
        }

        PayOrderDto payOrderDto = new PayOrderDto();
        // 生成退款单号
        String refundNo = idGenerator.snowflakeId() + "";
        payOrderEntity.setRefundNo(refundNo);

        BeanUtils.copyProperties(payOrderEntity, payOrderDto);

        if(StringUtils.isEmpty(payOrderDto.getCancelReason())){
            payOrderDto.setCancelReason(Constants.REFUND_DESC_ORGANIZER_CANCEL_ORDER);
        }
        payOrderDto.setTimestamp(String.valueOf(System.currentTimeMillis()/1000));
        payOrderDto.setNotifyUrl(lanTuWxPayBean.getDomain().concat(LANTU_REFUND_NOTIFY_URL));
        payOrderDto.setMchId(lanTuWxPayBean.getMchId());
        String sign = LantuPayUtil.createSignByRefund(payOrderDto);

        StringBuilder orderStr = new StringBuilder();
        orderStr.append("mch_id=").append(payOrderDto.getMchId())
                .append("&out_trade_no=").append(payOrderDto.getOrderNo())
                .append("&out_refund_no=").append(payOrderDto.getRefundNo()) // 我这里没有退款单号，就先暂时定为订单号
                .append("&timestamp=").append(payOrderDto.getTimestamp())
                .append("&refund_fee=").append(payOrderDto.getTotalPrice())
                .append("&refund_desc=").append(payOrderDto.getCancelReason())
                .append("&notify_url=").append(payOrderDto.getNotifyUrl())
                .append("&sign=").append(sign)
                ;

        HttpResponse<String> response = Unirest.post(REFUND_URL)
                .header("content-type", "application/x-www-form-urlencoded")
                .body(orderStr.toString())
                .asString();

        log.info("蓝兔支付响应结果：{}", JSON.toJSONString(response));
        if(null != response && 200 == response.getStatus()){
            String body = response.getBody();
            JSONObject jsonObject = JSONObject.parseObject(body);
            Integer code = (Integer) jsonObject.get("code");
            // code  0：成功  1：失败
            if(code != null && code == 0){
                // 更新订单信息
                String orderNo = payOrderDto.getOrderNo();
                PayOrderEntity payOrder = payOrderService.getOne(Wrappers.<PayOrderEntity>lambdaQuery()
                        .eq(PayOrderEntity::getOrderNo, orderNo).last("LIMIT 1"));
                if (payOrder == null) {
                    log.error("获取订单失败, orderNo: {}", orderNo);
                    // 返回订单号
                    return orderNo;
                }
                if (OrderStatusEnum.OrganizerCancel.equals(payOrder.getOrderStatus())) {
                    log.info("订单已退款, orderNo: {}", orderNo);
                    return null;
                }
                if (OrderStatusEnum.Cancelling.equals(payOrder.getOrderStatus())) {
                    log.info("正在退款中，请勿重复操作, orderNo: {}", orderNo);
                    return null;
                }
                payOrder.setOrderStatus(OrderStatusEnum.Cancelling);
                // 退款单号
                payOrder.setRefundNo(refundNo);
                // 退款原因
                if(StringUtils.isEmpty(payOrder.getCancelReason())){
                    payOrder.setCancelReason(Constants.REFUND_DESC_ORGANIZER_CANCEL_ORDER);
                }
                payOrder.updateById();

                // 发送订单取消成功通知
                PayOrderDto dto = new PayOrderDto();
                BeanUtils.copyProperties(payOrderEntity, dto);
//                dto.setUserName(userName);
//                dto.setOperateUserUid(userUid);
//                dto.setOrganizerUserUid(payOrderVO.getOrganizerUserUid());
                log.info("发送订单取消成功通知:{}", JSONObject.toJSONString(dto));
                domainEventUtil.publishEvent(EventAction.ORDER_CANCEL_SUCCESS, dto);
                return null;
            }
        }
        return payOrderDto.getOrderNo();
    }

    /**
     * 将支付的费用原路退回,如退还失败，返回订单号
     * @param list
     */
    private List<String> refundForCancelList(List<PayOrderEntity> list) {
        if(ListUtils.isEmpty(list)){
            return new ArrayList<>();
        }
        List<String> orderNoList = new ArrayList<>();
        for(PayOrderEntity entity : list){
            String orderNo = refundForCancel(entity);
            if(null == orderNo){
                continue;
            }
            orderNoList.add(orderNo);
        }
        return orderNoList;
    }


    /**
     * 查询当前活动的报名人数
     *
     * @param resourceUid
     * @return
     */
    @Override
    public Integer getLeaderNumByResourceUid(String resourceUid) {
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.RESOURCE_UID, resourceUid);
        queryWrapper.eq(SQLConf.APPLY_TYPE, OrderApplyTypeEnum.LEADER);
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        queryWrapper.eq(SQLConf.ORDER_STATUS, OrderStatusEnum.PaySuccess);
//        queryWrapper.select("count(uid) as leader_amount");
        return this.count(queryWrapper);
//        if (null == resultMap) {
//            return new HashMap<>(Constants.NUM_ZERO);
//        }
////        Integer amount = StringUtils.convertEvery(resultMap.get(SQLConf.AMOUNT), Integer.class);
////        Integer leaderAmount = StringUtils.convertEvery(resultMap.get(SQLConf.LEADER_AMOUNT), Integer.class);
////        Map<String, Object> amountMap = new HashMap<>(Constants.NUM_TWO);
////        amountMap.put(SQLConf.AMOUNT, amount == null ? 0 : amount);
////        amountMap.put(SQLConf.LEADER_AMOUNT, leaderAmount == null ? 0 : leaderAmount);
//        return resultMap;
    }

    /**
     * 查询当前活动的报名人数
     *
     * @param resourceUid
     * @return
     */
    @Override
    public Map<String, Object> getApplyUserNumByResourceUid(String resourceUid) {
        QueryWrapper<PayOrderEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.RESOURCE_UID, resourceUid);
        queryWrapper.eq(SQLConf.APPLY_TYPE, OrderApplyTypeEnum.PLAY);
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        queryWrapper.eq(SQLConf.ORDER_STATUS, OrderStatusEnum.PaySuccess);
        queryWrapper.select("sum(apply_user_num) as amount");
        Map<String, Object> resultMap = this.getMap(queryWrapper);
        if (null == resultMap) {
            return new HashMap<>(Constants.NUM_ZERO);
        }
//        Integer amount = StringUtils.convertEvery(resultMap.get(SQLConf.AMOUNT), Integer.class);
//        Integer leaderAmount = StringUtils.convertEvery(resultMap.get(SQLConf.LEADER_AMOUNT), Integer.class);
//        Map<String, Object> amountMap = new HashMap<>(Constants.NUM_TWO);
//        amountMap.put(SQLConf.AMOUNT, amount == null ? 0 : amount);
//        amountMap.put(SQLConf.LEADER_AMOUNT, leaderAmount == null ? 0 : leaderAmount);
        return resultMap;
    }
}
